﻿using Laharsub.Server.Wcf;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace Laharsub.Server.Wcf.Test
{


    /// <summary>
    ///This is a test class for InMemoryPubSubBackendTest and is intended
    ///to contain all InMemoryPubSubBackendTest Unit Tests
    ///</summary>
    [TestClass()]
    public class InMemoryPubSubBackendTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for InMemoryPubSubBackend Constructor
        ///</summary>
        [TestMethod()]
        public void InMemoryPubSubBackendConstructorTest()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
        }

        /// <summary>
        ///A test for BeginCreateTopic: creating one topic
        ///</summary>
        [TestMethod()]
        public void BeginCreateTopicTest()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            AsyncCallback callback = null;
            object state = new object();
            IAsyncResult actual = target.BeginCreateTopic(callback, state);
            Assert.IsNotNull(actual);
            Assert.IsTrue(actual.IsCompleted);
            Assert.IsTrue(actual.CompletedSynchronously);
            Assert.AreEqual(actual.AsyncState, state);
            Assert.IsNotNull(actual.AsyncWaitHandle);
            int result = target.EndCreateTopic(actual);
            Assert.IsTrue(result > 0);
        }

        /// <summary>
        ///A test for BeginCreateTopic: creating two topics
        ///</summary>
        [TestMethod()]
        public void BeginCreateTwoTopicsTest()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            AsyncCallback callback = null;
            object state = new object();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(callback, state));
            int topic2 = target.EndCreateTopic(target.BeginCreateTopic(callback, state));
            Assert.IsTrue(topic1 > 0);
            Assert.IsTrue(topic2 > topic1);
        }

        /// <summary>
        ///A test for BeginPublishMessage: one message
        ///</summary>
        [TestMethod()]
        public void BeginPublishMessageTest()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            string contentType = "text/plain";
            Stream body = new MemoryStream(Encoding.UTF8.GetBytes("Hello"));
            object state = new object();
            bool callbackCalled = false;
            IAsyncResult actual = target.BeginPublishMessage(topic1, contentType, body, new AsyncCallback(delegate (IAsyncResult r) { callbackCalled = true; }), state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            Assert.IsNotNull(actual.AsyncWaitHandle);            
            int result = target.EndPublishMessage(actual);
            Assert.IsTrue(actual.IsCompleted);
            Assert.IsFalse(actual.CompletedSynchronously);
            Assert.IsTrue(result > 0);
            Assert.IsTrue(callbackCalled);
        }

        /// <summary>
        ///A test for BeginPublishMessage: two messages
        ///</summary>
        [TestMethod()]
        public void BeginPublishTwoMessagesTest()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));
            Stream body2 = new MemoryStream(Encoding.UTF8.GetBytes("Hello2"));
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            int message2 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body2, null, null));
            Assert.IsTrue(message1 > 0);
            Assert.IsTrue(message2 > message1);
        }

        /// <summary>
        ///A test for BeginSubscribe: publish one message then subscribe
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest1()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, 1 } };
            TimeSpan timeout = TimeSpan.FromSeconds(10);
            object state = new object();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            bool callbackCalled = false;
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, new AsyncCallback(delegate(IAsyncResult r) { callbackCalled = true; }), state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNotNull(result);
            Assert.IsTrue(callbackCalled);
            PubSubMessage[] result1 = result.ToArray();
            Assert.IsTrue(result1.Length == 1);
            Assert.IsTrue(result1[0].MessageId == message1);
            Assert.IsTrue(result1[0].TopicId == topic1);
            Assert.IsTrue(result1[0].GetBodyAsString() == "Hello1");
        }

        void OnSubscribeCompleted(IAsyncResult result) { }

        /// <summary>
        ///A test for BeginSubscribe: publish two messages then subscribe
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest2()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, 1 } };
            TimeSpan timeout = TimeSpan.FromSeconds(10);
            object state = new object();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));
            Stream body2 = new MemoryStream(Encoding.UTF8.GetBytes("Hello2"));
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            int message2 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body2, null, null));
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, null, state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNotNull(result);
            PubSubMessage[] result1 = result.ToArray();
            Assert.IsTrue(result1.Length == 2);
            Assert.IsTrue(result1[0].MessageId == message1);
            Assert.IsTrue(result1[0].TopicId == topic1);
            Assert.IsTrue(result1[0].GetBodyAsString() == "Hello1");
            Assert.IsTrue(result1[1].MessageId == message2);
            Assert.IsTrue(result1[1].TopicId == topic1);
            Assert.IsTrue(result1[1].GetBodyAsString() == "Hello2");
        }

        /// <summary>
        ///A test for BeginSubscribe: publish two messages then subscribe from the second one
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest3()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            TimeSpan timeout = TimeSpan.FromSeconds(10);
            object state = new object();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));
            Stream body2 = new MemoryStream(Encoding.UTF8.GetBytes("Hello2"));
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            int message2 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body2, null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, message2 } };
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, null, state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNotNull(result);
            PubSubMessage[] result1 = result.ToArray();
            Assert.IsTrue(result1.Length == 1);
            Assert.IsTrue(result1[0].MessageId == message2);
            Assert.IsTrue(result1[0].TopicId == topic1);
            Assert.IsTrue(result1[0].GetBodyAsString() == "Hello2");
        }

        /// <summary>
        ///A test for BeginSubscribe: publish two messages to different topics then subscribe to one topic
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest4()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            int topic2 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            TimeSpan timeout = TimeSpan.FromSeconds(10);
            object state = new object();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));
            Stream body2 = new MemoryStream(Encoding.UTF8.GetBytes("Hello2"));
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            int message2 = target.EndPublishMessage(target.BeginPublishMessage(topic2, contentType, body2, null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, 1 } };
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, null, state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNotNull(result);
            PubSubMessage[] result1 = result.ToArray();
            Assert.IsTrue(result1.Length == 1);
            Assert.IsTrue(result1[0].MessageId == message1);
            Assert.IsTrue(result1[0].TopicId == topic1);
            Assert.IsTrue(result1[0].GetBodyAsString() == "Hello1");
        }

        /// <summary>
        ///A test for BeginSubscribe: publish two messages to different topics then subscribe to both topics
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest5()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            int topic2 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            TimeSpan timeout = TimeSpan.FromSeconds(10);
            object state = new object();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));
            Stream body2 = new MemoryStream(Encoding.UTF8.GetBytes("Hello2"));
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            int message2 = target.EndPublishMessage(target.BeginPublishMessage(topic2, contentType, body2, null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, 1 }, { topic2, 1 } };
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, null, state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNotNull(result);
            PubSubMessage[] result1 = result.ToArray();
            Assert.IsTrue(result1.Length == 2);
            Assert.IsTrue(result1[0].MessageId == message1);
            Assert.IsTrue(result1[0].TopicId == topic1);
            Assert.IsTrue(result1[0].GetBodyAsString() == "Hello1");
            Assert.IsTrue(result1[1].MessageId == message2);
            Assert.IsTrue(result1[1].TopicId == topic2);
            Assert.IsTrue(result1[1].GetBodyAsString() == "Hello2");
        }

        /// <summary>
        ///A test for BeginSubscribe: subscrive and time out
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest6()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, 1 } };
            TimeSpan timeout = TimeSpan.FromMilliseconds(5);
            object state = new object();
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, null, state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNull(result);
        }

        /// <summary>
        ///A test for BeginSubscribe: subscribe then publish
        ///</summary>
        [TestMethod()]
        public void BeginSubscribeTest7()
        {
            InMemoryPubSubBackend target = new InMemoryPubSubBackend();
            int topic1 = target.EndCreateTopic(target.BeginCreateTopic(null, null));
            IDictionary<int, int> subscriptions = new Dictionary<int, int> { { topic1, 0 } };
            TimeSpan timeout = TimeSpan.FromSeconds(10);
            object state = new object();
            string contentType = "text/plain";
            Stream body1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello1"));            
            IAsyncResult actual = target.BeginSubscribe(subscriptions, timeout, null, state);
            Assert.IsNotNull(actual);
            Assert.AreEqual(actual.AsyncState, state);
            Assert.IsNotNull(actual.AsyncWaitHandle);
            int message1 = target.EndPublishMessage(target.BeginPublishMessage(topic1, contentType, body1, null, null));
            IEnumerable<PubSubMessage> result = target.EndSubscribe(actual);
            Assert.IsNotNull(result);
            Assert.IsFalse(actual.CompletedSynchronously);
            Assert.IsTrue(actual.IsCompleted);
            PubSubMessage[] result1 = result.ToArray();
            Assert.IsTrue(result1.Length == 1);
            Assert.IsTrue(result1[0].MessageId == message1);
            Assert.IsTrue(result1[0].TopicId == topic1);
            Assert.IsTrue(result1[0].GetBodyAsString() == "Hello1");
        }
    }
}
